<template>
  <div class="personTrack"></div>
</template>
<script setup lang='ts'>
import { useViewportStore } from '@/store/viewport'
import { useAuthStore } from '@/store/auth';
import { storeToRefs } from 'pinia';
import { gsap } from 'gsap'
import { CSS2DObject, GLTFLoader } from 'three/examples/jsm/Addons.js'
import { watch, shallowRef, onMounted, createVNode, render, onUnmounted } from 'vue'
import { AnimationMixer, CatmullRomCurve3, Clock } from 'three'
import { getPath } from '@/utils/getPath'
import { findClosestT, findTrackPath, mergeCurvesSequentially } from '@/utils/findTrackPath'
import { cloneDeep } from 'lodash'
import BTrack1 from '@/components/b-track1.vue'
import useAnimationFrame from '@/hooks/useAnimationFrame'


const viewportStore = useViewportStore()
const { scene, curveNetwork, baseVec } = storeToRefs(viewportStore)
const timeline = gsap.timeline() // 创建时间线
const authStore = useAuthStore()
const { historyData } = storeToRefs(authStore)

const trackData = shallowRef([])
onMounted(async () => {
  watch(() => historyData.value.personList, async (val, oldVal) => {
    for (let index = 0; index < val.length; index++) {
      const item = cloneDeep(val[index]);
      item.jzPoint = window.jzPoints[item.jzNo];
      if (!item.jzPoint) {
        console.warn('未找到数据', item) // 打印警告信息
        continue; // 跳过当前循环
      }
      const road = getPath(item.jzPoint);
      if (!road) {
        console.warn('未找到道路', item) // 打印警告信息
        continue; // 跳过当前循环
      }
      item.curve = road.geometry.parameters.path;
      item.uuid = road.uuid;

      let oldItem = trackData.value.find((track) => track.peopleNo === item.peopleNo)
      if (oldItem) {
        const [newItem] = mergeCurvesSequentially([item])
        const resultPath = findTrackPath([oldItem, newItem], curveNetwork.value.graph, curveNetwork.value.connectionMap);
        runPeople(resultPath, oldItem)
        oldItem = {
          ...oldItem,
          ...newItem
        }
      } else {
        const { scene: model, animations } = await loadGLTFModel()
        model.scale.set(3, 3, 3)
        const mixer = new AnimationMixer(model);
        const clip = mixer.clipAction(animations[0])
        const [newItem] = mergeCurvesSequentially([item])
        trackData.value.push(newItem)
        newItem.model = model
        newItem.mixer = mixer
        newItem.clip = clip
        newItem.model.position.copy(newItem.point).sub(baseVec.value);
        const label = createdTracklLabel(newItem.name)
        newItem.label = label
        newItem.model.add(label)
        scene.value?.add(newItem.model)
      }
    }
    trackData.value.forEach((track) => {
      const has = val.find(val => val.peopleNo === track.peopleNo)
      if (!has) {
        track.model.remove(track.label)
        track.model.removeFromParent()
      }
    })
  }, { immediate: true })
})

onUnmounted(() => {
  trackData.value.forEach((track) => {
      track.model.remove(track.label)
      track.model.removeFromParent()
  })
})


const loader = new GLTFLoader()
const BASE_URL = import.meta.env.BASE_URL
function loadGLTFModel () {
  return new Promise((resolve, reject) => {
    loader.load(
      BASE_URL + 'model/people.glb',
      (gltf) => {
        resolve(gltf)
      },
      undefined,
      (error) => {
        reject(error)
      }
    )
  })
}

function runPeople (resultPath, item) {
  for (let i = 0; i < resultPath.length; i++) {
    if (resultPath[i].path.length < 2) {
      continue
    }
    const curve = new CatmullRomCurve3(resultPath[i].path);
    const tA = findClosestT(curve, resultPath[i].path[0])
    const tB = findClosestT(curve, resultPath[i].path[resultPath[i].path.length - 1])
    const obj = { t: tA }; // 中间变量存储当前t值
    item.clip.play()
    timeline.to(obj, {
      t: tB,
      duration: 5,
      ease: "linear",
      onUpdate: () => {
        // 根据当前t值更新物体位置
        const position = curve.getPoint(obj.t).sub(baseVec.value);
        item.model.position.copy(position);

        const tangent = curve.getTangent(obj.t);
        item.model.lookAt(position.clone().add(tangent));
      },
    })
  }
}

function createdTracklLabel (text) {
  const container = document.createElement('div')
  const vm = createVNode(BTrack1, {
    name: text,
  }, null)
  render(vm, container)
  const label = new CSS2DObject(container.firstElementChild as Node)
  label.Vnode = vm
  return label
}

const clock = new Clock();
useAnimationFrame(() => {
  const delta = clock.getDelta();
  trackData.value.forEach((track) => {
    track.mixer?.update(delta)
  })
})
</script>
<style lang="scss" scoped></style>
